﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using System.Windows.Forms;
using Application = Autodesk.Revit.ApplicationServices.Application;
using ZhuXingFamilys.ExportExcel.entity;
using NPOI.SS.Formula.Functions;
using Floor = Autodesk.Revit.DB.Floor;
using System.Windows.Controls;
using ZhuXingFamilys.MainViewModel;
using Category = Autodesk.Revit.DB.Category;
using ZhuXingFamilys.ExportExcel.utils;
using System.Runtime.Serialization;
using System.Xml;

namespace ZhuXingFamilys.ExportExcel
{
	public class LianJie : IExternalEventHandler
	{
		public List<RulesNode> rulesNodeList { get; set; }
        Transaction trans;
        public void Execute(UIApplication uiApp)
		{
			Document doc = uiApp.ActiveUIDocument.Document;
            trans = new Transaction(doc, "LianJie");

            if (rulesNodeList != null)
			{
				foreach(RulesNode rulesNode in rulesNodeList)
				{
					if (rulesNode != null && rulesNode.rulesList != null && rulesNode.rulesList.Count != 0)
					{
						foreach(Rules rules in rulesNode.rulesList)
						{
							if (rules.IsSelected == 1 && !string.IsNullOrEmpty(rules.BuiltInCategory1) && !string.IsNullOrEmpty(rules.BuiltInCategory2))
                            {
								BuiltInCategory builtInCategory1 = (BuiltInCategory)int.Parse(rules.BuiltInCategory1);
								BuiltInCategory builtInCategory2 = (BuiltInCategory)int.Parse(rules.BuiltInCategory2);
                                // 根据 Category 和 FamilyName 两个条件过滤需要进行扣减的族实例
                                FilteredElementCollector filteredElements = new FilteredElementCollector(doc);
								IList<Element> beam = filteredElements.OfCategory(builtInCategory1).ToList<Element>();
								IList<Element> beamjc = beam.Where(b => getElementName(doc,b).Equals(rules.NodeName)).ToList();
                                KJPD(doc, rules, beamjc, builtInCategory2, rules.Deduction);
                            }
						}
					}
				}
			}
			MessageBox.Show("扣减完成", "提示");
		}



		/// <summary>
		/// 扣减判断
		/// </summary>
		/// <param name="doc"></param>
		/// <param name="rules">扣减规则</param>
		/// <param name="elements">需要进行扣减的构件列表</param>
		/// <param name="bc">构件类型枚举</param>
		/// <param name="familyName">需要取消或与构件连接的构建的familyName</param>
		private void KJPD(Document doc , Rules rules ,IList<Element> elements, BuiltInCategory bc, string familyName = null)
		{
            // 无影响 取消连接
            if (rules.Opt == 0)
            {
                trans.Start();
                foreach (Element e in elements)
                {
                    // 取消与板的链接
                    CancelConnection(doc, e, bc, familyName);
                }
                trans.Commit();
            }
            // 扣除前
            else if (rules.Opt == 1)
            {
                // 开启事务
                trans.Start();
                foreach (Element e in elements)
                {
                    // 取消连接 这步必须做 不然如果已经连接 则获取不到相交
                    CancelConnection(doc, e, bc, familyName);
                }
                // 提交事务
                trans.Commit();

                // 开启事务
                trans.Start();
                foreach (Element e in elements)
                {
                    // 获得相交
                    List<Element> intersectElements = GetIntersectElements(e, bc, false, familyName);
                    foreach (Element floors in intersectElements)
                    {
                        // 连接
                        KJ(doc, e, floors);
                    }
                }
                // 提交事务
                trans.Commit();
            }
            // 扣除后
            else if (rules.Opt == 2)
            {
                trans.Start();
                foreach (Element e in elements)
                {
                    CancelConnection(doc, e, bc, familyName);
                }
                trans.Commit();

                trans.Start();
                foreach (Element e in elements)
                {
                    List<Element> intersectElements = GetIntersectElements(e, bc, false, familyName);
                    foreach (Element floors in intersectElements)
                    {
                        KJ(doc, floors, e);
                    }
                }
                trans.Commit();
            }
		}

		/// <summary>
		/// 扣减方法 实现连接
		/// </summary>
		/// <param name="doc"></param>
		/// <param name="a"></param>
		/// <param name="b"></param>
		private void KJ(Document doc, Element a, Element b)//被调用的扣减程序
		{
			if (JoinGeometryUtils.AreElementsJoined(doc, a, b))//判断a、b是否连接（例：结构柱扣梁中，a、b在这里代表的是结构柱与梁）
			{
				JoinGeometryUtils.UnjoinGeometry(doc, a, b);//a、b若已经连接则取消连接
			}
			try
			{
				JoinGeometryUtils.JoinGeometry(doc, a, b);//连接a、b
				if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, a, b))//判断扣减效果是否为a扣减b（前面的会扣减后面的）
				{
					JoinGeometryUtils.SwitchJoinOrder(doc, a, b);//否则的话则转换为a扣减b
				}
			}
			catch (Exception e)
			{
				//trans.Commit();
				//MessageBox.Show(e.Message);
			}
		}
		/// <summary>
		/// 根据条件取消element已经存在的连接
		/// </summary>
		/// <param name="doc"></param>
		/// <param name="ele"></param>
		/// <param name="type">类型</param>
		/// <param name="builtInCategory"></param>
		/// <param name="familyName">族名称</param>
		private void CancelConnection(Document doc , Element ele , BuiltInCategory builtInCategory, string familyName)
		{
			// 获得所有已连接
			List<ElementId> joinedElementIds = JoinGeometryUtils.GetJoinedElements(doc, ele).ToList();
			foreach (ElementId id in joinedElementIds)
			{
				Element e1 = doc.GetElement(id);
				Category catColumn = doc.Settings.Categories.get_Item(builtInCategory);

				if (builtInCategory != BuiltInCategory.INVALID && familyName != null)
				{
					//if (e1.GetType() == type && e1.Category.Name == categoryName)
					if (e1.Category.Id.Equals(catColumn.Id) && getElementName(doc, e1).Contains(familyName))
					{
						if (JoinGeometryUtils.AreElementsJoined(doc, ele, e1))//判断a、b是否连接（例：结构柱扣梁中，a、b在这里代表的是结构柱与梁）
						{
							JoinGeometryUtils.UnjoinGeometry(doc, ele, e1);//a、b若已经连接则取消连接
						}
					}
				}
				else
				{
					if (e1.Category.Id.Equals(catColumn.Id))
					{
						if (JoinGeometryUtils.AreElementsJoined(doc, ele, e1))//判断a、b是否连接（例：结构柱扣梁中，a、b在这里代表的是结构柱与梁）
						{
							JoinGeometryUtils.UnjoinGeometry(doc, ele, e1);//a、b若已经连接则取消连接
						}
					}
				}
				
			}
		}


		/// <summary>
		/// 获取相交元素 boundingBox
		/// </summary>
		/// <param name="element">根据图元找相交</param>
		/// <param name="category">类别</param>
		/// <param name="contain">是否包含自身</param>
		/// <param name="familyName">过滤掉不包含此族名称的element</param>
		/// <returns>查找结果</returns>
		private List<Element> GetIntersectElements(Element element, BuiltInCategory category, bool contain = false, string familyName = null)
		{
			List<Element> listElement = new List<Element>();
			Document doc = element.Document;
			BoundingBoxXYZ boundingBoxXyz = element.get_BoundingBox(doc.ActiveView);
			Outline outline = new Outline(boundingBoxXyz.Min, boundingBoxXyz.Max);
			BoundingBoxIntersectsFilter boundFilter = new BoundingBoxIntersectsFilter(outline);
			ElementCategoryFilter filter2 = new ElementCategoryFilter(category);
			LogicalAndFilter filter3 = new LogicalAndFilter(boundFilter, filter2);
			FilteredElementCollector collector = new FilteredElementCollector(doc);
			listElement = collector.WherePasses(filter3).WhereElementIsNotElementType().ToList();

			if (contain == false)
			{
				listElement.RemoveAll(m => m.Id == element.Id);
			}
			if(familyName != null)
			{
                //listElement = listElement.Where(f => f.get_Parameter(BuiltInParameter.ELEM_FAMILY_PARAM).AsValueString().Contains(familyName)).ToList();
                listElement = listElement.Where(f => getElementName(doc,f).Contains(familyName)).ToList();
            }

			return listElement;
		}

		// 获取项目名称
		private string getElementName(Document doc, Element ele )
		{
			ICollection<ElementId> vt = ele.GetValidTypes();
			foreach (var eid in vt)
			{
				Element e = doc.GetElement(eid);
				if (e.Name == ele.Name)//找到当前所选图元的族类型
				{
					Parameter p = e.LookupParameter("项目名称");
					if(p != null && p.AsString() != null)
					{
						return p.AsString();
					}
				}
			}
			return "无项目名称";
		}

		public string GetName()
		{
			return "LianJie";
		}
	}
}
